// 4.6. object

// 限制⼀般对象

// 限制person对象的具体内容，使⽤【,】分隔，问号代表可选属性
let person: { name: string; age?: number };

// 限制car对象的具体内容，使⽤【;】分隔，必须有price和color属性，其他属性不去限制，有没有都⾏
let car: { price: number; color: string; [propName: string]: any };

// 限制student对象的具体内容，使⽤【回⻋】分隔
let student: {
  name: string;
  age?: number;
};

// 以下代码均⽆警告
car = {
  price: 10,
  brand: 'BMW',
  color: 'red',
};

// 限制函数的参数、返回值
let demo: (a: number, b: number) => number;

demo = function (a, b) {
  return a + b;
};

// 限制数组
let arr1: number[]; // 数字数组  等价于 let arr1: Array<number>;
let arr2: string[]; // 字符串数组  等价于 let arr2: Array<string>;

// 4.7. tuple
let t: [string, number];
t = ['hello', 123];

// 4.8. enum

// 定义⼀个枚举
enum Color {
  Red,
  Blue,
  Black,
  Gold,
}
// console.log(Color);

// 定义⼀个枚举，并指定其初识数值
enum Color2 {
  Red = 6,
  Blue,
  Black,
  Gold,
}
// console.log(Color2);

// 定义⼀个枚举，并将枚举成员指定字符串值
enum Color3 {
  Red = 'red',
  Blue = 'blue',
  Black = 'black',
  Gold = 'gold',
}
// console.log(Color2);

// 定义一个phone变量，并设置对齐进行限制
let phone: { name: string; price: number; color: Color3 };

phone = {
  name: 'iphone',
  price: 10,
  color: Color3.Red,
};

// console.log(phone);
if (phone.color === Color3.Red) {
  // console.log('手机是红色的');
}

// 5. 自定义类型
// 自定义类型，可以更灵活的限制类型

// 性别类型
enum Gender {
  Male,
  Female,
}

// 自定义一个年级类型（高一、高二、高三）
type Grade = 1 | 2 | 3;
// 自定义一个学生类型，包含姓名、年龄、性别、年级
type Student = {
  name: string;
  age?: number;
  gender: Gender;
  grade: Grade;
};

// 定义两个学生变量： s1 和 s2
let s1: Student;
let s2: Student;
s1 = {
  name: '张三',
  age: 20,
  gender: Gender.Male,
  grade: 3,
};
s2 = {
  name: '李四',
  gender: Gender.Female,
  grade: 2,
};

// 6. 抽象类
// 常规类
class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

const p1 = new Person('张三', 20);
const p2 = new Person('李四', 30);

// 继承
class Teacher extends Person {
  constructor(name: string, age: number) {
    super(name, age);
  }
}

// 抽象类：不能实例化，只能被继承，抽象类里有抽象方法
abstract class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  // 抽象方法：只有声明，没有具体实现
  abstract eat(): void;
}

// 7. 接口
// 接口梳理
// 1. 接口用于限制一个类中包含哪些属性和方法
// 2. 接口不能实例化，只能被类实现
interface Career {
  // 属性声明
  jobName: string;
  jobDesc: string;
  // 方法声明
  work(): void;
}

// Doctor实现Career接口
class Doctor implements Career {
  jobName: string;
  jobDesc: string;
  constructor(name: string, desc: string) {
    this.jobName = name;
    this.jobDesc = desc;
  }
  work() {
    // console.log('医生工作，需要做的事情是', this.jobDesc);
  }
}

// 2. 接口是可以重复声明的
// Person接口
interface PersonInter {
  // 属性声明
  name: string;
  age: number;
}
// Person接口
interface PersonInter {
  // 方法声明
  work(): void;
}

// Engineer类继承PersonInter
class Enginneer implements PersonInter {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  work() {
    // console.log('工程师工作，需要做的事情是', '写代码');
  }
}

// 3. 接口与自定义类型的区别
// 接口可以：
// 1. 可以当自定义类型使用
// 2. 可以限制类的结构




// 9. 泛型
// 定义一个函数或类时，有些行


